package com.dmc.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.dmc.conf.PayCallBackConfig;
import com.dmc.dict.*;
import com.dmc.mapper.PaymentMapper;
import com.dmc.model.Payment;
import com.dmc.model.RestResp;
import com.dmc.model.RestRespResult;
import com.dmc.service.OrdersService;
import com.dmc.util.DecimalUtil;
import com.dmc.util.SessionUtil;
import com.dmc.util.id.IdUtil;
import com.dmc.vo.PaymentVo;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

/**
 * 第三方支付接口--支付宝
 */
@Service
@Transactional
public class AliPayPayServiceImpl extends AbstractPayServiceImpl implements InitializingBean {
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    public static final String ALIPAY_RETURN_CODE_SUCCESS = "10000";
    public static final String ALIPAY_RETURN_CODE_FAIL = "20000";
    public static final String ALIPAY_RESULT_CODE_SUCCESS = "SUCCESS";
    public static final String ALIPAY_RESULT_CODE_FAIL = "FAIL";
    public static final String ALIPAY_RESULT_CODE_WAIT_BUYER_PAY = "WAIT_BUYER_PAY";// 交易创建，等待买家付款。
    public static final String ALIPAY_RESULT_CODE_TRADE_CLOSED = "TRADE_CLOSED";// 在指定时间段内未支付时关闭的交易；在交易完成全额退款成功时关闭的交易。
    public static final String ALIPAY_RESULT_CODE_TRADE_SUCCESS = "TRADE_SUCCESS";// 交易成功，且可对该交易做操作，如：多级分润、退款等。
    public static final String ALIPAY_RESULT_CODE_TRADE_FINISHED = "TRADE_FINISHED";// 交易成功且结束，即不可再做任何操作。


    private AlipayClient alipayClient;

    @Autowired
    private PayCallBackConfig payCallBackConfig;

    @Autowired
    private PaymentMapper paymentMapper;

    @Autowired
    private OrdersService ordersService;

    @Override
    public void afterPropertiesSet() throws Exception {
        Map<String, String> aliPayAppInfo = AbstractPayServiceImpl.payMap.get(PayTypeDict.PAY_TYPE_ALIPAY.getCn() + PayModeDict.PAY_MODE_MINI_NATIVE.getCn());
        alipayClient = new DefaultAlipayClient(
                "https://openapi.alipay.com/gateway.do", aliPayAppInfo.get("appId"),
                aliPayAppInfo.get("privateKey") , "json", "utf-8", aliPayAppInfo.get("publicKey"),"RSA2");
    }




    @Override
    public RestRespResult<Map<String, String>> pay(PaymentVo payment) {
        replaceOrderIdToNo(payment);
        RestRespResult<Map<String, String>> restResp = null;
        Map<String, String> map = new HashMap<String, String>();
        //获取支付宝商户号等信息
        String payModel = payment.getPayModel();
        String payType = payment.getPayType();
        Integer orderType = payment.getOrderType();
        Long checkoutId = payment.getCheckoutId();
        Map<String, String> aliPayAppInfo = AbstractPayServiceImpl.payMap.get(payType + payModel);
        if(aliPayAppInfo == null){
            return RestRespResult.error( RestResp.ERROR, "参数错误,支付宝支付只支持扫码支付");
        }
        Long userId = payment.getUserId();
        String orderId = payment.getOrderId();
        //订单相关前置处理
        String amount = payment.getAmount();
        if(OrderTypeDict.ORDER_TYPE_GOODS.getCn() == orderType){
            //如果是商品订单,则从订单获取
            BigDecimal orderFinalAmount=ordersService.getFinalAmountByOrderNo(orderId);
            amount = DecimalUtil.mul(orderFinalAmount.toString(),"100").setScale(2).toString();
        }
        //根据订单号查询对应支付单
        Payment paymentCheckout = getPayment(userId,PaymentTypeDict.PAYMENT_TYPE_PAY.getCn(),payment.getOrderType(),orderId,checkoutId,false,new BigDecimal(amount));
        JSONObject jsonObject = payOrderExePre(paymentCheckout.getCheckoutId(),PaymentTypeDict.PAYMENT_TYPE_PAY.getCn(), orderId, orderType,amount);

        String body = jsonObject.getString("orderDetail");
        //新增还是更新
        boolean save = paymentCheckout.getId() == null;
        StringBuffer goods = new StringBuffer();
        goods.append("订单详情");
        //根据订单获取订单商品详情
        String subject = "支付描述";
        //商户门店编号
        String storeId = "123";
        //转换为元
        amount = (new BigDecimal(amount).divide(new BigDecimal("100"),2,BigDecimal.ROUND_HALF_UP)).toPlainString();
        String notifyUrl = payCallBackConfig.getAliPay();
        aliPayAppInfo.get("appId");
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        request.setNotifyUrl(notifyUrl);
        request.setBizContent("{\"out_trade_no\":\"" + paymentCheckout.getCheckoutId() + "\", \"total_amount\":"
                + amount + ", \"subject\":\"" + subject + "\"" + ", \"body\":\"" + body + "\"}");
        String qrCode = null;
        try {
            AlipayTradePrecreateResponse response = alipayClient.execute(request);
            final String code = response.getCode();
            final String msg = response.getMsg();
            paymentCheckout.setStartTime(new Date());
            paymentCheckout.setPaymentResult(JSON.toJSONString(response));
            if("10000".contentEquals(code)){
                qrCode = response.getQrCode();
                paymentCheckout.setPaymentStatus(PaymentStatusDict.PAYMENT_STATUS_SUCCESS.getCn());
                map.put("checkoutId",paymentCheckout.getCheckoutId()+"");
                restResp = RestRespResult.ok("支付宝支付获取二维码成功");
            }else{
                paymentCheckout.setPaymentStatus(PaymentStatusDict.PAYMENT_STATUS_FAIL.getCn());
                restResp =  RestRespResult.error( RestResp.ERROR, msg);
            }
            paymentCheckout.setTradeStatus(code);
        } catch (Exception e) {
            log.info("AliPayPayServiceImpl pay params:{}", ToStringBuilder.reflectionToString(payment),e);
            return RestRespResult.error( RestResp.ERROR, "获取支付宝支付二维码异常");
        }
        if(save){
            paymentCheckout.setId(IdUtil.generateId());
            paymentCheckout.setCreateTime(new Date());
            paymentMapper.insert(paymentCheckout);
        }else{
            paymentMapper.updateById(paymentCheckout);
        }

        map.put("qrCode",qrCode);
        restResp.setData(map);
        return restResp;
    }

    @Override
    public RestRespResult<Map<String, String>>  queryPay(PaymentVo payment) {
        replaceOrderIdToNo(payment);
        String orderId = payment.getOrderId();
        Long userId = payment.getUserId();
        Payment paymentCheckout = getPayment(userId,PaymentTypeDict.PAYMENT_TYPE_PAY.getCn(),payment.getOrderType(),orderId,payment.getCheckoutId(),true,null);
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        request.setBizContent("{\"out_trade_no\":\"" + paymentCheckout.getCheckoutId() + "\"}");
        AlipayTradeQueryResponse response = null;
        try {
            response = alipayClient.execute(request);
            final String code = response.getCode();
            final String msg = response.getMsg();
            if(!"10000".contentEquals(code)){
                return RestRespResult.error( RestResp.ERROR, msg);
            }
        }catch (Exception e){
            log.info("AliPayPayServiceImpl queryPay params:{}", ToStringBuilder.reflectionToString(payment),e);
            return RestRespResult.error( RestResp.ERROR, "获取支付宝支付二维码异常");
        }
        RestRespResult restResp = RestRespResult.ok("获取支付宝支付详情成功");
        restResp.setData(response);
        return restResp;
    }

    @Override
    public RestRespResult<String> payCallBack(HttpServletRequest request) {
        RestRespResult restResp = null;
        Map<String, String> parameterMap = callbackParamToMap(request);
        log.error("AliPayPayServiceImpl payCallBack parameterMap:{}",JSON.toJSONString(parameterMap));
        //验证是否是支付宝的实际回调 TODO
        String out_trade_no = parameterMap.get("out_trade_no");
        String trade_status = parameterMap.get("trade_status");
        boolean updateOrder = false;
        if (AliPayPayServiceImpl.ALIPAY_RESULT_CODE_TRADE_FINISHED.equalsIgnoreCase(trade_status) ||
                AliPayPayServiceImpl.ALIPAY_RESULT_CODE_TRADE_SUCCESS.equalsIgnoreCase(trade_status) ){
            updateOrder = true;
            restResp = RestRespResult.ok("支付宝回调成功");
            restResp.setData( "success");
        }else{
            restResp = RestRespResult.error(RestResp.ERROR, "支付宝回调失败");
            restResp.setData("fail");
        }
        try {
            Payment paymentCheckout = paymentMapper.getByCheckoutId(Long.valueOf(out_trade_no));
            if(updateOrder && paymentCheckout.getCompleteTime()==null){
                //支付成功,更新订单支付状态
                paymentCheckout.setCompleteTime(new Date());
                String orderNo = paymentCheckout.getOrderId();
                log.debug("3支付回调时对订单相关处理payCallBackOrderExePre");
                payCallBackOrderExePre(orderNo,paymentCheckout.getOrderType(),3, DistriButionPayTypeDict.DISTRIBUTION_PAY_TYPE_2.getCn());
                paymentCheckout.setPaymentResult(JSON.toJSONString(parameterMap));
                paymentMapper.updateById(paymentCheckout);
            }
        }catch (Exception e){
            log.error("AliPayPayServiceImpl payCallBack param:{}", JSON.toJSONString(parameterMap),e);
        }
        return restResp;
    }

    /**
     * 将支付宝回调参数封装成map
     * @param request
     * @return
     */
    private Map<String, String> callbackParamToMap(HttpServletRequest request){
        Map<String, String> result = new HashMap<>();
        Map<String, String[]> parameterMap = request.getParameterMap();
        if(!CollectionUtils.isEmpty(parameterMap)){
            for (String key : parameterMap.keySet()) {
                String[] strings = parameterMap.get(key);
                if (strings!=null && strings.length>0){
                    result.put(key,strings[0]);
                }
            }
        }
        return result;
    }

    /**
     * 验证访问是否是支付宝发起
     * @param parameterMap
     */
    private void checkAliPayRequest(Map<String, String> parameterMap){
        // 签名验证
        Map<String, String> data = new TreeMap<String, String>();
        data.put("notify_time", parameterMap.get("notify_time"));
        data.put("notify_type", parameterMap.get("notify_type"));
        data.put("notify_id", parameterMap.get("notify_id"));
        data.put("trade_no", parameterMap.get("trade_no"));
        data.put("app_id", parameterMap.get("app_id"));
        data.put("out_trade_no", parameterMap.get("out_trade_no"));
        if (parameterMap.get("out_biz_no")!=null) {
            data.put("out_biz_no", parameterMap.get("out_biz_no"));
        }
        if (parameterMap.get("buyer_id")!=null) {
            data.put("buyer_id", parameterMap.get("buyer_id"));
        }
        if (parameterMap.get("buyer_logon_id")!=null) {
            data.put("buyer_logon_id", parameterMap.get("buyer_logon_id"));
        }
        if (parameterMap.get("seller_id")!=null) {
            data.put("seller_id", parameterMap.get("seller_id"));
        }
        if (parameterMap.get("seller_email")!=null) {
            data.put("seller_email", parameterMap.get("seller_email"));
        }
        if (parameterMap.get("open_id")!=null) {
            data.put("open_id", parameterMap.get("open_id"));
        }
        if (parameterMap.get("trade_status")!=null) {
            data.put("trade_status", parameterMap.get("trade_status"));
        }
        if (parameterMap.get("total_amount")!=null) {
            data.put("total_amount", parameterMap.get("total_amount"));
        }
        if (parameterMap.get("receipt_amount")!=null) {
            data.put("receipt_amount", parameterMap.get("receipt_amount"));
        }
        if (parameterMap.get("invoice_amount")!=null) {
            data.put("invoice_amount", parameterMap.get("invoice_amount"));
        }
        if (parameterMap.get("buyer_pay_amount")!=null) {
            data.put("buyer_pay_amount", parameterMap.get("buyer_pay_amount"));
        }
        if (parameterMap.get("point_amount")!=null) {
            data.put("point_amount", parameterMap.get("point_amount"));
        }
        if (parameterMap.get("refund_fee")!=null) {
            data.put("refund_fee", parameterMap.get("refund_fee"));
        }
        if (parameterMap.get("send_back_fee")!=null) {
            data.put("send_back_fee", parameterMap.get("send_back_fee"));
        }
        if (parameterMap.get("subject")!=null) {
            data.put("subject", parameterMap.get("subject"));
        }
        if (parameterMap.get("body")!=null) {
            data.put("body", parameterMap.get("body"));
        }
        if (parameterMap.get("gmt_create")!=null) {
            data.put("gmt_create", parameterMap.get("gmt_create"));
        }
        if (parameterMap.get("gmt_payment")!=null) {
            data.put("gmt_payment", parameterMap.get("gmt_payment"));
        }
        if (parameterMap.get("gmt_refund")!=null) {
            data.put("gmt_refund", parameterMap.get("gmt_refund"));
        }
        if (parameterMap.get("gmt_close")!=null) {
            data.put("gmt_close", parameterMap.get("gmt_close"));
        }
        if (parameterMap.get("fund_bill_list")!=null) {
            data.put("fund_bill_list", parameterMap.get("fund_bill_list"));
        }
        String sign_type = parameterMap.get("sign_type");

        if (sign_type.contentEquals("RSA2")) {

        }
    }

    @Override
    public RestRespResult<String> transfer(PaymentVo payment) {
        return RestRespResult.error( RestResp.ERROR, "转账暂时不支持转账");
    }

    @Override
    public RestRespResult<String> refund(PaymentVo payment) {
        replaceOrderIdToNo(payment);
        RestRespResult restResp = null;
        String orderId = payment.getOrderId();
        //根据订单号查询对应支付单
        Payment paymentCheckout = getPayment(null,PaymentTypeDict.PAYMENT_TYPE_PAY.getCn(),null,orderId,payment.getCheckoutId(),true,null);
        Integer orderType = paymentCheckout.getOrderType();
        //退款时,订单前置处理
        JSONObject jsonObject = refundOrderExePre(PaymentTypeDict.PAYMENT_TYPE_REFUND.getCn(), orderId, orderType);
        Long userId = paymentCheckout.getUserId();
        Payment paymentRefund = getPayment(userId,PaymentTypeDict.PAYMENT_TYPE_REFUND.getCn(),payment.getOrderType(),orderId,null,false,new BigDecimal(payment.getAmount()));
        boolean save = paymentRefund.getId()==null;
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        String amount = payment.getAmount();
        amount = (new BigDecimal(amount).divide(new BigDecimal("100"),2,BigDecimal.ROUND_HALF_UP)).toPlainString();
        String refundReason = payment.getReason();
        refundReason = StringUtils.isBlank(refundReason)?"正常退款":refundReason;
        request.setBizContent(
                "{\"out_trade_no\":\"" + paymentCheckout.getCheckoutId() + "\"," +
                        " \"refund_amount\":" + amount + "," +
                        " \"out_request_no\":" + paymentRefund.getCheckoutId() + "," +
                        " \"refund_reason\":\"" + refundReason + "\"}");
        AlipayTradeRefundResponse response = null;
        try {
            response = alipayClient.execute(request);
            final String code = response.getCode();
            final String msg = response.getMsg();
            if("10000".contentEquals(code)){
                restResp = RestRespResult.ok("发起退款成功");
                paymentRefund.setPaymentStatus(PaymentStatusDict.PAYMENT_STATUS_SUCCESS.getCn());
                paymentRefund.setCompleteTime(new Date());
                refundBackOrderExePre(orderId,orderType,jsonObject.get("order"));
            }else{
                paymentRefund.setPaymentStatus(PaymentStatusDict.PAYMENT_STATUS_FAIL.getCn());
                restResp = RestRespResult.error( RestResp.ERROR, msg);
            }
        }catch (Exception e){
            log.info("AliPayPayServiceImpl refund params:{}", ToStringBuilder.reflectionToString(payment),e);
            return RestRespResult.error( RestResp.ERROR, "支付宝退款异常");
        }
        paymentRefund.setPaymentResult(JSON.toJSONString(response));
        paymentRefund.setTradeStatus(response.getCode());
        if(save){
            paymentRefund.setId(IdUtil.generateId());
            paymentRefund.setCreateTime(new Date());
            paymentMapper.insert(paymentRefund);
        }else{
            paymentMapper.updateById(paymentRefund);
        }
        return restResp;
    }

    @Override
    public RestRespResult<String> queryRefund(PaymentVo payment) {

        return null;
    }

    @Override
    public RestResp refundCallBack(PaymentVo payment) {
        return null;
    }


}
